package pl.edu.pb.wi.pwnography.controller;

import java.io.IOException;
import java.util.Arrays;
import java.util.logging.Logger;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import pl.edu.pb.wi.pwnography.model.ParsedData;
import pl.edu.pb.wi.pwnography.model.form.FileUploadForm;
import pl.edu.pb.wi.pwnography.parsing.TextFileParser;
import pl.edu.pb.wi.pwnography.session.FileList;

@Controller
@RequestMapping("/files")
public class FileManagement {
    private static final Logger log = Logger.getLogger(FileManagement.class
	    .getName());
    private static final String DELETE_SUCCESS = "Plik o nazwie '%s' został pomyślnie usunięty.";
    private static final String DELETE_ERROR = "Wysąpił błąd w trakcie usuwania pliku o numerze: %d";
    private static final String UPLOAD_PARSE_ERROR = "Wystąpił błąd związany z odczytem pliku.";
    private static final String UPLOAD_SUCCESS = "Wczytanie pliku zakończyło się powodzeniem.";
    private static final String LIST_EMPTY = "Brak plików.";
    private static final String SELECT_FILE_SUCCESS = "Plik %d oraz jego najnowsza rewizja zostały ustawione jako aktywne.";
    private static final String SELECT_FILE_ERROR = "Wystąpił błąd w trakcie wyboru pliku %d oraz jego najnowszej rewizji.";
    private static final String SELECT_REVISION_ERROR = "Wystąpił błąd przy wyborze rewizji %d dla pliku %d";
    private static final String SELECT_REVISION_SUCCESS = "Jako aktywny zestaw danych została ustawiona rewizja %d";
    private static final String HISTORY_ERROR = "Wystąpił błąd w trakcie generowania historii zmian pliku o numerze: %d";
    private static final String DOWNLOAD_ERROR = "Wystąpił błąd.";

    @Autowired
    private FileList fileList;

    public void setFileList(FileList fileList) {
	this.fileList = fileList;
    }

    @RequestMapping(value = "upload", method = RequestMethod.POST)
    public String fileUpload(
	    @ModelAttribute("form") @Valid FileUploadForm form,
	    BindingResult result, Model model) throws IOException {
	try {
	    TextFileParser tfp = new TextFileParser(form);
	    fileList.addFile(tfp.parseData(form.getHaveColumnNames()));

	    model.addAttribute("successMsgs",
		    Arrays.asList(new String[] { UPLOAD_SUCCESS }));
	} catch (Exception ex) {
	    log.info(ex.getMessage());
	    model.addAttribute("errorMsgs",
		    Arrays.asList(new String[] { UPLOAD_PARSE_ERROR }));
	}

	return "welcome";
    }

    @RequestMapping("download/{fileId}/revision/{revisionId}")
    public @ResponseBody
    ResponseEntity<String> fileDownload(@PathVariable("fileId") int fileId,
	    @PathVariable("revisionId") int revisionId,
	    HttpServletResponse response) {
	HttpHeaders responseHeaders = new HttpHeaders();
	responseHeaders.add("Content-Type", "text/html; charset=utf-8");

	String responseString = null;
	try {
	    responseString = (revisionId != -1) ? fileList
		    .getParsedData(fileId).getRevisionData(revisionId)
		    .toHtmlString() : fileList.getParsedData(fileId)
		    .toHtmlString();
	} catch (Exception ex) {
	    log.info(ex.getMessage());

	    responseString = DOWNLOAD_ERROR;
	}

	return new ResponseEntity<String>(responseString, responseHeaders,
		HttpStatus.CREATED);
    }

    @RequestMapping("list")
    public String fileList(Model model) {
	if (fileList.getFileList() != null && fileList.getFileList().size() > 0) {
	    model.addAttribute("fileList", fileList.getFileList());
	} else {
	    model.addAttribute("infoMsgs",
		    Arrays.asList(new String[] { LIST_EMPTY }));
	}

	return "/file/list";
    }

    @RequestMapping("delete/{fileId}")
    public String deleteFile(@PathVariable("fileId") int fileId, Model model) {
	log.info(String.format("Trying to delete file with ID: %d", fileId));

	try {
	    String name = fileList.remove(fileId).getFileName();

	    model.addAttribute("successMsgs",
		    Arrays.asList(new String[] { String.format(DELETE_SUCCESS,
			    name) }));
	} catch (Exception e) {
	    log.info(String.format("Removing file failed. Exception: %s",
		    e.getMessage()));

	    model.addAttribute("errorMsgs", Arrays.asList(new String[] { String
		    .format(DELETE_ERROR, fileId) }));
	}

	return "forward:/files/list";
    }

    @RequestMapping("history/{fileId}")
    public String fileHistory(@PathVariable("fileId") int fileId, Model model) {
	log.info(String.format("Trying to view file with ID: %d history",
		fileId));

	try {
	    ParsedData pd = fileList.getParsedData(fileId);
	    model.addAttribute("fileId", fileId);
	    model.addAttribute("fileName", pd.getFileName());
	    model.addAttribute("historyList", pd.getChangeList());
	} catch (Exception e) {
	    log.info(String.format(
		    "Checking file history failed. Exception: %s",
		    e.getMessage()));

	    model.addAttribute("errorMsgs", Arrays.asList(new String[] { String
		    .format(HISTORY_ERROR, fileId) }));
	}

	return "/file/history";
    }

    @RequestMapping("select/{fileId}/revision/{revisionId}")
    public String selectFileRevision(@PathVariable("fileId") int fileId,
	    @PathVariable("revisionId") int revisionId, Model model) {
	log.info(String.format(
		"Trying to select file with ID: %d revision number %d", fileId,
		revisionId));

	try {
	    ParsedData file = fileList.getParsedData(fileId);
	    file.revertToRevision(revisionId);

	    fileList.setActiveFileId(fileId);

	    model.addAttribute("successMsgs", Arrays
		    .asList(new String[] { String.format(
			    SELECT_REVISION_SUCCESS, revisionId) }));

	    return String.format("forward:/files/history/%d", fileId);
	} catch (Exception e) {
	    log.info(String.format(
		    "Selecting file %d revision %d failed. Exception: %s",
		    fileId, revisionId, e.getMessage()));

	    model.addAttribute("errorMsgs", Arrays.asList(new String[] { String
		    .format(SELECT_REVISION_ERROR, revisionId, fileId) }));
	}

	return "forward:/files/list";
    }

    @RequestMapping("select/{fileId}")
    public String selectFile(@PathVariable("fileId") int fileId, Model model) {
	log.info(String.format("Trying to select file with ID: %d", fileId));

	try {
	    ParsedData file = fileList.getParsedData(fileId);
	    file.revertToNewestRevision();

	    fileList.setActiveFileId(fileId);

	    model.addAttribute("successMsgs", Arrays
		    .asList(new String[] { String.format(SELECT_FILE_SUCCESS,
			    fileList.getActiveFileId()) }));
	} catch (Exception e) {
	    log.info(String.format(
		    "Selecting file %d newest failed. Exception: %s", fileId,
		    e.getMessage()));

	    model.addAttribute("errorMsgs", Arrays.asList(new String[] { String
		    .format(SELECT_FILE_ERROR, fileId) }));
	}

	return "forward:/files/list";
    }

}
